home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 15 / CU Amiga Magazine's Super CD-ROM 15 (1997)(EMAP Images)(GB)[!][issue 1997-10].iso / CUCD / Graphics / Ghostscript / source / gxcht.c < prev    next >
C/C++ Source or Header  |  1997-03-20  |  18KB  |  585 lines

  1. /* Copyright (C) 1993, 1996, 1997 Aladdin Enterprises.  All rights reserved.
  2.   
  3.   This file is part of Aladdin Ghostscript.
  4.   
  5.   Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND.  No author
  6.   or distributor accepts any responsibility for the consequences of using it,
  7.   or for whether it serves any particular purpose or works at all, unless he
  8.   or she says so in writing.  Refer to the Aladdin Ghostscript Free Public
  9.   License (the "License") for full details.
  10.   
  11.   Every copy of Aladdin Ghostscript must include a copy of the License,
  12.   normally in a plain ASCII text file named PUBLIC.  The License grants you
  13.   the right to copy, modify and redistribute Aladdin Ghostscript, but only
  14.   under certain conditions described in the License.  Among other things, the
  15.   License requires that the copyright notice and this notice be preserved on
  16.   all copies.
  17. */
  18.  
  19. /* gxcht.c */
  20. /* Color halftone rendering for Ghostscript imaging library */
  21. #include "memory_.h"
  22. #include "gx.h"
  23. #include "gserrors.h"
  24. #include "gsutil.h"        /* for id generation */
  25. #include "gxfixed.h"
  26. #include "gxmatrix.h"
  27. #include "gxdevice.h"
  28. #include "gxcmap.h"
  29. #include "gxdcolor.h"
  30. #include "gxistate.h"
  31. #include "gzht.h"
  32.  
  33. /* Define the size of the tile buffer allocated on the stack. */
  34. #define tile_longs_LARGE 256
  35. #define tile_longs_SMALL 64
  36. #if arch_small_memory
  37. #  define tile_longs_allocated tile_longs_SMALL
  38. #  define tile_longs tile_longs_SMALL
  39. #else
  40. #  define tile_longs_allocated tile_longs_LARGE
  41. #  define tile_longs\
  42.      (gs_if_debug_c('.') ? tile_longs_SMALL : tile_longs_LARGE)
  43. #endif
  44.  
  45. /* Define the colored halftone device color type. */
  46. private dev_color_proc_load(gx_dc_ht_colored_load);
  47. private dev_color_proc_fill_rectangle(gx_dc_ht_colored_fill_rectangle);
  48. private struct_proc_enum_ptrs(dc_ht_colored_enum_ptrs);
  49. private struct_proc_reloc_ptrs(dc_ht_colored_reloc_ptrs);
  50. const gx_device_color_procs
  51.   gx_dc_procs_ht_colored =
  52.     { gx_dc_ht_colored_load, gx_dc_ht_colored_fill_rectangle,
  53.       gx_dc_default_fill_masked,
  54.       dc_ht_colored_enum_ptrs, dc_ht_colored_reloc_ptrs
  55.     };
  56. #undef gx_dc_type_ht_colored
  57. const gx_device_color_procs _ds *gx_dc_type_ht_colored = &gx_dc_procs_ht_colored;
  58. #define gx_dc_type_ht_colored (&gx_dc_procs_ht_colored)
  59. /* GC procedures */
  60. #define cptr ((gx_device_color *)vptr)
  61. private ENUM_PTRS_BEGIN(dc_ht_colored_enum_ptrs) return 0;
  62.     ENUM_PTR(0, gx_device_color, colors.colored.c_ht);
  63. ENUM_PTRS_END
  64. private RELOC_PTRS_BEGIN(dc_ht_colored_reloc_ptrs) {
  65.     RELOC_PTR(gx_device_color, colors.colored.c_ht);
  66. } RELOC_PTRS_END
  67. #undef cptr
  68.  
  69. /* Forward references. */
  70. private void set_ht_colors(P6(gx_color_index [16], gx_strip_bitmap *[4],
  71.   const gx_device_color *, gx_device *, gx_ht_cache *[4], int));
  72. private void set_color_ht(P9(gx_strip_bitmap *, int, int, int, int, int, int,
  73.   const gx_color_index [16], const gx_strip_bitmap *[4]));
  74.  
  75. /* Define a table for expanding 8x1 bits to 8x4. */
  76. private const bits32 far_data expand_8x1_to_8x4[256] = {
  77. #define x16(c)\
  78.   c+0, c+1, c+0x10, c+0x11, c+0x100, c+0x101, c+0x110, c+0x111,\
  79.   c+0x1000, c+0x1001, c+0x1010, c+0x1011, c+0x1100, c+0x1101, c+0x1110, c+0x1111
  80.     x16(0x00000000), x16(0x00010000), x16(0x00100000), x16(0x00110000),
  81.     x16(0x01000000), x16(0x01010000), x16(0x01100000), x16(0x01110000),
  82.     x16(0x10000000), x16(0x10010000), x16(0x10100000), x16(0x10110000),
  83.     x16(0x11000000), x16(0x11010000), x16(0x11100000), x16(0x11110000)
  84. #undef x16
  85. };
  86.  
  87. /* Prepare to use a colored halftone, by loading the default cache. */
  88. private int
  89. gx_dc_ht_colored_load(gx_device_color *pdevc, const gs_imager_state *pis,
  90.   gx_device *ignore_dev, gs_color_select_t select)
  91. {    gx_device_halftone *pdht = pis->dev_ht;
  92.     gx_ht_order *porder = &pdht->components[0].corder;
  93.     gx_ht_cache *pcache = pis->ht_cache;
  94.  
  95.     if ( pcache->order.bits != porder->bits )
  96.       gx_ht_init_cache(pcache, porder);
  97.     /* Set the cache pointers in the default order. */
  98.     pdht->order.cache = porder->cache = pcache;
  99.     return 0;
  100. }
  101.  
  102. /* Fill a rectangle with a colored halftone. */
  103. /* Note that we treat this as "texture" for RasterOp. */
  104. private int
  105. gx_dc_ht_colored_fill_rectangle(const gx_device_color *pdevc, int x, int y,
  106.   int w, int h, gx_device *dev, gs_logical_operation_t lop,
  107.   const gx_rop_source_t *source)
  108. {    ulong tbits[tile_longs_allocated];
  109.     const uint tile_bytes = tile_longs * size_of(long);
  110.     gx_strip_bitmap tiles;
  111.     gx_rop_source_t no_source;
  112.     const gx_device_halftone *pdht = pdevc->colors.colored.c_ht;
  113.     int depth = dev->color_info.depth;
  114.     int nplanes = dev->color_info.num_components;
  115.     gx_color_index colors[16];    
  116.     gx_strip_bitmap *sbits[4];
  117.     gx_ht_cache *caches[4];
  118.     int code = 0;
  119.     int raster;
  120.     uint size_x;
  121.     int dw, dh;
  122.     int lw = pdht->lcm_width, lh = pdht->lcm_height;
  123.  
  124.     if ( w <= 0 || h <= 0 )
  125.       return 0;
  126.     /* Colored halftone patterns are unconditionally opaque. */
  127.     lop &= ~lop_T_transparent;
  128.     tiles.data = (byte *)tbits;
  129.     if ( pdht->components == 0 )
  130.       caches[0] = caches[1] = caches[2] = caches[3] = pdht->order.cache;
  131.     else
  132.     {    gx_ht_order_component *pocs = pdht->components;
  133.         caches[0] = pocs[pdht->color_indices[0]].corder.cache;
  134.         caches[1] = pocs[pdht->color_indices[1]].corder.cache;
  135.         caches[2] = pocs[pdht->color_indices[2]].corder.cache;
  136.         caches[3] = pocs[pdht->color_indices[3]].corder.cache;
  137.     }
  138.     set_ht_colors(colors, sbits, pdevc, dev, caches, nplanes);
  139.     /* If the LCM of the plane cell sizes is smaller than */
  140.     /* the rectangle being filled, compute a single tile and */
  141.     /* let tile_rectangle do the replication. */
  142.     if ( (w > lw || h > lh) &&
  143.          (raster = bitmap_raster(lw * depth)) <= tile_bytes / lh
  144.        )
  145.       { /*
  146.          * The only reason we need to do fit_fill here is that if the
  147.          * device is a clipper, the caller might be counting on it to do
  148.          * all necessary clipping.  Actually, we should clip against the
  149.          * device's clipping box, not the default....
  150.          */
  151.         fit_fill(dev, x, y, w, h);
  152.         /* Check to make sure we still have a big rectangle. */
  153.         if ( w > lw || h > lh )
  154.           { tiles.raster = raster;
  155.         tiles.rep_width = tiles.size.x = lw;
  156.         tiles.rep_height = tiles.size.y = lh;
  157.         tiles.id = gs_next_ids(1);
  158.         tiles.rep_shift = tiles.shift = 0;
  159.         /* See below for why we need to cast bits. */
  160.         set_color_ht(&tiles, 0, 0, lw, lh,
  161.                  depth, nplanes, colors,
  162.                  (const gx_strip_bitmap **)sbits);
  163.         if ( source == NULL && lop_no_S_is_T(lop) )
  164.           return (*dev_proc(dev, strip_tile_rectangle))(dev, &tiles,
  165.                 x, y, w, h,
  166.                 gx_no_color_index, gx_no_color_index,
  167.                 pdevc->phase.x, pdevc->phase.y);
  168.         if ( source == NULL )
  169.           set_rop_no_source(source, no_source, dev);
  170.         return (*dev_proc(dev, strip_copy_rop))(dev, source->sdata,
  171.                 source->sourcex, source->sraster, source->id,
  172.                 (source->use_scolors ? source->scolors : NULL),
  173.                 &tiles, NULL,
  174.                 x, y, w, h,
  175.                 pdevc->phase.x, pdevc->phase.y,
  176.                 rop3_know_S_0(lop));
  177.           }
  178.       }
  179.     tiles.id = gx_no_bitmap_id;
  180.     size_x = w * depth;
  181.     raster = bitmap_raster(size_x);
  182.     if ( raster > tile_bytes )
  183.       {    /*
  184.          * We can't even do an entire line at once.  See above for
  185.          * why we do the X equivalent of fit_fill here.
  186.          */
  187.         if ( x < 0 )
  188.           w += x, x = 0;
  189.         if ( x > dev->width - w )
  190.           w = dev->width - x;
  191.         if ( w <= 0 )
  192.           return 0;
  193.         size_x = w * depth;
  194.         raster = bitmap_raster(size_x);
  195.         if ( raster > tile_bytes )
  196.           { dw = tile_bytes * 8 / depth;
  197.             size_x = dw * depth;
  198.             raster = bitmap_raster(size_x);
  199.             dh = 1;
  200.             goto fit;
  201.           }
  202.     }
  203.     /* Do as many lines as will fit. */
  204.     dw = w;
  205.     dh = tile_bytes / raster;
  206.     if ( dh > h )
  207.       dh = h;
  208. fit:    /* Now the tile will definitely fit. */
  209.     tiles.raster = raster;
  210.     tiles.rep_width = tiles.size.x = size_x / depth;
  211.     tiles.rep_shift = tiles.shift = 0;
  212.     while ( w )
  213.     {    int cy = y, ch = dh, left = h;
  214.         tiles.rep_height = tiles.size.y = ch;
  215.         for ( ; ; )
  216.         {    /* The cast in the following statement is bogus, */
  217.             /* but some compilers won't accept an array type, */
  218.             /* and won't accept the ** type without a cast. */
  219.             set_color_ht(&tiles, x, cy, dw, ch,
  220.                      depth, nplanes, colors,
  221.                      (const gx_strip_bitmap **)sbits);
  222.             if ( lop_no_S_is_T(lop) )
  223.               { code = (*dev_proc(dev, copy_color))(dev,
  224.                     tiles.data, 0, raster,
  225.                     gx_no_bitmap_id, x, cy, dw, ch);
  226.               }
  227.             else
  228.               { gs_logical_operation_t lop_st = rop3_swap_S_T(lop);
  229.                 code = (*dev_proc(dev, strip_copy_rop))(dev,
  230.                     tiles.data, 0, raster,
  231.                     gx_no_bitmap_id,
  232.                     NULL,
  233.                     NULL,
  234.                     pdevc->colors.binary.color /*arb*/,
  235.                     x, cy, dw, ch, 0, 0,
  236.                     rop3_know_T_0(lop_st));
  237.               }
  238.             if ( code < 0 )
  239.                 return code;
  240.             if ( !(left -= ch) )
  241.                 break;
  242.             cy += ch;
  243.             if ( ch > left )
  244.                 tiles.rep_height = tiles.size.y = ch = left;
  245.         }
  246.         if ( !(w -= dw) )
  247.           break;
  248.         x += dw;
  249.         if ( dw > w)
  250.           dw = w, tiles.rep_width = tiles.size.x = size_x / depth;
  251.     }
  252.     return code;
  253. }
  254.  
  255. /*
  256.  * We construct color halftone tiles out of 3 or 4 "planes".
  257.  * Each plane specifies halftoning for one component (R/G/B or C/M/Y/K).
  258.  */
  259.  
  260. /* Set up the colors and the individual plane halftone bitmaps. */
  261. private void
  262. set_ht_colors(gx_color_index colors[16], gx_strip_bitmap *sbits[4],
  263.   const gx_device_color *pdc, gx_device *dev, gx_ht_cache *caches[4],
  264.   int nplanes)
  265. {    gx_color_value v[2][4];
  266.     static const ulong no_bitmap_data[] =
  267.      { 0, 0, 0, 0, 0, 0, 0, 0 };
  268.     static gx_strip_bitmap no_bitmap =
  269.      { 0, sizeof(ulong), { sizeof(ulong) * 8, countof(no_bitmap_data) },
  270.        gx_no_bitmap_id, 1, 1, 0, 0
  271.      };
  272.     gx_color_value max_color = dev->color_info.dither_colors - 1;
  273.     int plane_mask = 0;
  274.  
  275.     no_bitmap.data = (byte *)no_bitmap_data;    /* actually const */
  276. #define cb(i) pdc->colors.colored.c_base[i]
  277. #define cl(i) pdc->colors.colored.c_level[i]
  278. #define set_plane_color(i)\
  279. {    uint q = cb(i);\
  280.     uint r = cl(i);\
  281.     v[0][i] = fractional_color(q, max_color);\
  282.     if ( r == 0 )\
  283.       v[1][i] = v[0][i], sbits[i] = &no_bitmap;\
  284.     else\
  285.       v[1][i] = fractional_color(q+1, max_color),\
  286.       sbits[i] = &gx_render_ht(caches[i], r)->tiles,\
  287.       plane_mask |= 1 << (i);\
  288. }
  289. #define map8(m) m(0), m(1), m(2), m(3), m(4), m(5), m(6), m(7)
  290.     set_plane_color(0);
  291.     set_plane_color(1);
  292.     set_plane_color(2);
  293.     if ( nplanes == 3 )
  294.       {
  295. #define map_rgb(i)\
  296.   colors[i] = map1rgb(v[(i) & 1][0], v[((i) & 2) >> 1][1], v[(i) >> 2][2])
  297.         gx_color_value alpha = pdc->colors.colored.alpha;
  298.         if ( alpha == gx_max_color_value )
  299.         {    
  300. #ifdef DEBUG
  301. #  define map1rgb(r, g, b) gx_map_rgb_color(dev, r, g, b)
  302. #else
  303.             dev_proc_map_rgb_color((*map)) =
  304.               dev_proc(dev, map_rgb_color);
  305. #  define map1rgb(r, g, b) (*map)(dev, r, g, b)
  306. #endif
  307.             map8(map_rgb);
  308. #undef map1rgb
  309.         }
  310.         else
  311.         {
  312. #ifdef DEBUG
  313. #  define map1rgb(r, g, b) gx_map_rgb_alpha_color(dev, r, g, b, alpha)
  314. #else
  315.             dev_proc_map_rgb_alpha_color((*map)) =
  316.               dev_proc(dev, map_rgb_alpha_color);
  317. #  define map1rgb(r, g, b) (*map)(dev, r, g, b, alpha)
  318. #endif
  319.             map8(map_rgb);
  320. #undef map1rgb
  321.         }
  322.       }
  323.     else
  324.       {
  325. #define map_cmyk(i)\
  326.   colors[i] = map1cmyk(v[(i) & 1][0], v[((i) & 2) >> 1][1],\
  327.                v[((i) & 4) >> 2][2], v[(i) >> 3][3])
  328. #ifdef DEBUG
  329. #  define map1cmyk(r, g, b, w) gx_map_cmyk_color(dev, r, g, b, w)
  330. #else
  331.         dev_proc_map_cmyk_color((*map)) =
  332.           dev_proc(dev, map_cmyk_color);
  333. #  define map1cmyk(r, g, b, w) (*map)(dev, r, g, b, w)
  334. #endif
  335.         set_plane_color(3);
  336.         /*
  337.          * For CMYK output, especially if the input was RGB, it's
  338.          * common for one or more of the components to be zero.
  339.          * Each zero component can cut the cost of color mapping in
  340.          * half, so it's worth doing a little checking here.
  341.          */
  342. #define m1(i) map_cmyk(i)
  343. #define m2(i,d) m1(i), m1(i+d)
  344. #define m4(i,d1,d2) m2(i, d1), m2(i + d2, d1)
  345.         switch ( plane_mask )
  346.           {
  347.           case 15: m4(8, 1, 2); m4(12, 1, 2);
  348.           case  7: m4(4, 1, 2);
  349. c3:          case  3: m2(2, 1);
  350. c1:          case  1: m1(1); break;
  351.           case 14: m4(8, 2, 4);
  352.           case  6: m2(4, 2);
  353. c2:          case  2: m1(2); break;
  354.           case 13: m4(8, 1, 4);
  355.           case  5: m2(4, 1); goto c1;
  356.           case 12: m2(8, 4);
  357.           case  4: m1(4); break;
  358.           case 11: m4(8, 1, 2); goto c3;
  359.           case 10: m2(8, 2); goto c2;
  360.           case  9: m2(8, 1); goto c1;
  361.           case  8: m1(8); break;
  362.           case  0: ;
  363.           }
  364.         m1(0);
  365. #undef m1
  366. #undef m2
  367. #undef m4
  368. #undef map1cmyk
  369.       }
  370. #undef map8
  371. #undef set_plane_color
  372. #undef cb
  373. #undef cl
  374. }
  375.  
  376. /* Render the combined halftone. */
  377. private void
  378. set_color_ht(
  379.     gx_strip_bitmap *ctiles,  /* the output tile; data, raster, size are set */
  380.     int px,            /* the initial phase of the output tile */
  381.     int py,
  382.     int w,            /* how much of the tile to set */
  383.     int h,
  384.     int depth,        /* depth of tile (4, 8, 16, 24, 32) */
  385.     int nplanes,        /* # of source planes, 3 or 4 */
  386.     const gx_color_index colors[16], /* the actual colors for the tile, */
  387.                 /* actually [1 << nplanes] */
  388.     const gx_strip_bitmap *sbits[4]    /* the bitmaps for the planes, */
  389.                 /* actually [nplanes] */
  390. )
  391. {    /* Note that the planes are specified in the order RGB or CMYK, but */
  392.     /* the indices used for the internal colors array are BGR or KYMC. */
  393.  
  394.     int x, y;
  395.     struct tile_cursor_s {
  396.         int tile_shift;        /* X shift per copy of tile */
  397.         int xoffset;
  398.         int xshift;
  399.         uint xbytes;
  400.         int xbits;
  401.         const byte *row;
  402.         const byte *tdata;
  403.         uint raster;
  404.         const byte *data;
  405.         int bit_shift;
  406.     } cursor[4];
  407.     int dbytes = depth >> 3;
  408.     uint dest_raster = ctiles->raster;
  409.     byte *dest_row =
  410.       ctiles->data + dest_raster * (h - 1) + (w * depth) / 8;
  411.     int endx = w + px;
  412.  
  413.     if_debug6('h',
  414.           "[h]color_ht: x=%d y=%d w=%d h=%d nplanes=%d depth=%d\n",
  415.           px, py, w, h, nplanes, depth);
  416.  
  417.     /* Do one-time cursor initialization. */
  418.     {    int lasty = h - 1 + py;
  419. #define set_start(i, c, btile)\
  420. { int tw = btile->size.x;\
  421.   int bx = ((c.tile_shift = btile->shift) == 0 ? endx :\
  422.         endx + lasty / btile->size.y * c.tile_shift) % tw;\
  423.   int by = lasty % btile->size.y;\
  424.   c.xoffset = bx >> 3;\
  425.   c.xshift = 8 - (bx & 7);\
  426.   c.xbytes = (tw - 1) >> 3;\
  427.   c.xbits = ((tw - 1) & 7) + 1;\
  428.   c.tdata = btile->data;\
  429.   c.raster = btile->raster;\
  430.   c.row = c.tdata + by * c.raster;\
  431.   if_debug5('h', "[h]plane %d: size=%d,%d bx=%d by=%d\n",\
  432.         i, tw, btile->size.y, bx, by);\
  433. }
  434.         set_start(0, cursor[0], sbits[0]);
  435.         set_start(1, cursor[1], sbits[1]);
  436.         set_start(2, cursor[2], sbits[2]);
  437.         if ( nplanes == 4 )
  438.             set_start(3, cursor[3], sbits[3]);
  439. #undef set_start
  440.     }
  441.  
  442.     /* Now compute the actual tile. */
  443.     for ( y = h; ; dest_row -= dest_raster )
  444.     {    byte *dest = dest_row;
  445. #define set_row(c)\
  446.   {    c.data = c.row + c.xoffset;\
  447.     c.bit_shift = c.xshift;\
  448.   }
  449.         set_row(cursor[0]);
  450.         set_row(cursor[1]);
  451.         set_row(cursor[2]);
  452.         if ( nplanes == 4 )
  453.         {    set_row(cursor[3]);
  454.         }
  455. #undef set_row
  456.         --y;
  457.         for ( x = w; x > 0; )
  458.         {    bits32 indices;
  459.             int nx, i;
  460.             register uint bits;
  461. /* Get the next byte's worth of bits.  Note that there may be */
  462. /* excess bits set beyond the 8th. */
  463. #define next_bits(c)\
  464. {    if ( c.data > c.row )\
  465.     {    bits = ((c.data[-1] << 8) | *c.data) >> c.bit_shift;\
  466.         c.data--;\
  467.     }\
  468.     else\
  469.     {    bits = *c.data >> c.bit_shift;\
  470.         c.data += c.xbytes;\
  471.         if ( (c.bit_shift -= c.xbits) < 0 )\
  472.         {    bits |= *c.data << -c.bit_shift;\
  473.             c.bit_shift += 8;\
  474.         }\
  475.         else\
  476.         {    bits |= ((c.data[-1] << 8) | *c.data) >> c.bit_shift;\
  477.             c.data--;\
  478.         }\
  479.     }\
  480. }
  481.             if ( nplanes == 4 )
  482.             {    next_bits(cursor[3]);
  483.                 indices = expand_8x1_to_8x4[bits & 0xff] << 1;
  484.             }
  485.             else
  486.                 indices = 0;
  487.             next_bits(cursor[2]);
  488.             indices = (indices | expand_8x1_to_8x4[bits & 0xff]) << 1;
  489.             next_bits(cursor[1]);
  490.             indices = (indices | expand_8x1_to_8x4[bits & 0xff]) << 1;
  491.             next_bits(cursor[0]);
  492.             indices |= expand_8x1_to_8x4[bits & 0xff];
  493. #undef next_bits
  494.             nx = min(x, 8);        /* 1 <= nx <= 8 */
  495.             x -= nx;
  496.             switch ( dbytes )
  497.             {
  498.             case 0:            /* 4 */
  499.                 i = nx;
  500.                 if ( (x + nx) & 1 )
  501.                   { /* First pixel is even nibble. */
  502.                     *dest = (*dest & 0xf) +
  503.                       ((byte)colors[(uint)indices & 0xf] << 4);
  504.                     indices >>= 4;
  505.                     --i;
  506.                   }
  507.                 /* Now 0 <= i <= 8. */
  508.                 for ( ; (i -= 2) >= 0; indices >>= 8 )
  509.                   *--dest =
  510.                     (byte)colors[(uint)indices & 0xf] +
  511.                     ((byte)colors[((uint)indices >> 4) & 0xf]
  512.                      << 4);
  513.                 /* Check for final odd nibble. */
  514.                 if ( i & 1 )
  515.                   *--dest = (byte)colors[(uint)indices & 0xf];
  516.                 break;
  517.             case 4:            /* 32 */
  518.                 for ( i = nx; --i >= 0; indices >>= 4 )
  519.               {    gx_color_index tcolor =
  520.                     colors[(uint)indices & 0xf];
  521.                 dest -= 4;
  522.                 dest[3] = (byte)tcolor;
  523.                 dest[2] = (byte)(tcolor >> 8);
  524.                 tcolor >>= 16;
  525.                 dest[1] = (byte)tcolor;
  526.                 dest[0] = (byte)((uint)tcolor >> 8);
  527.               }
  528.                 break;
  529.             case 3:            /* 24 */
  530.                 for ( i = nx; --i >= 0; indices >>= 4 )
  531.               {    gx_color_index tcolor =
  532.                     colors[(uint)indices & 0xf];
  533.                 dest -= 3;
  534.                 dest[2] = (byte)tcolor;
  535.                 dest[1] = (byte)((uint)tcolor >> 8);
  536.                 tcolor >>= 16;
  537.                 dest[0] = (byte)((uint)tcolor >> 8);
  538.               }
  539.                 break;
  540.             case 2:            /* 16 */
  541.                 for ( i = nx; --i >= 0; indices >>= 4 )
  542.               {    uint tcolor =
  543.                     (uint)colors[(uint)indices & 0xf];
  544.                 dest -= 2;
  545.                 dest[1] = (byte)tcolor;
  546.                 dest[0] = (byte)(tcolor >> 8);
  547.               }
  548.                 break;
  549.             case 1:            /* 8 */
  550.                 for ( i = nx; --i >= 0; indices >>= 4 )
  551.                     *--dest = (byte)colors[(uint)indices & 0xf];
  552.                 break;
  553.             }
  554.         }
  555.         if ( y == 0 )
  556.             break;
  557.  
  558. #define step_row(c, i)\
  559.   if ( c.row > c.tdata )\
  560.     c.row -= c.raster;\
  561.   else    /* wrap around to end of tile, taking shift into account */\
  562.     { c.row += c.raster * (sbits[i]->size.y - 1);\
  563.       if ( c.tile_shift )\
  564.     { if ( (c.xshift += c.tile_shift) >= 8 )\
  565.         { if ( (c.xoffset -= c.xshift >> 3) < 0 )\
  566.         { /* wrap around in X */\
  567.           int bx = c.xoffset + sbits[i]->size.x;\
  568.           c.xoffset = bx >> 3;\
  569.           c.xshift = 8 - (bx & 7);\
  570.         }\
  571.           else\
  572.         c.xshift &= 7;\
  573.         }\
  574.     }\
  575.     }
  576.  
  577.         step_row(cursor[0], 0);
  578.         step_row(cursor[1], 1);
  579.         step_row(cursor[2], 2);
  580.         if ( nplanes == 4)
  581.           step_row(cursor[3], 3);
  582. #undef step_row
  583.     }
  584. }
  585.